#ifndef __REACTOR_H__
#define __REACTOR_H__

#include <errno.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <poll.h>
#include <sys/epoll.h>
#include <errno.h>
#include <sys/time.h>
#include <stdlib.h>
#include <fcntl.h>
#include "content_node.h"
#include "public.h"


typedef int (*RCALLBACK)(int fd);


#define REMAIN_LENGTH 1024


typedef struct conn
{
    int fd;
    char remain_buffer[REMAIN_LENGTH];
    int remain_len;
    node remain_link;

    int sent; // 已发送的字节数（跟踪发送进度）
    int idx;  // 单个包已发送的数据

    RCALLBACK in_callback;
    RCALLBACK out_callback;

    node wlink; // 发送链表节点，业务层向链表中添加处理好后的数据
    node rlink; // 接收链表节点（如果约定包的协议，也可以处理半包问题和粘包问题）。业务层从链表中读取数据

} conn;

static int epfd_ = 0;    // 全局变量，方面设置事件,如果用于多线程记得加锁。static 修饰后，仅当前文件可访问
static conn *conn_list_; // static 修饰后，仅当前文件可访问
int init_epfd()
{
    epfd_ = epoll_create(1); // epoll_create只能在程序执行时能调用，这里封装成函数
    return epfd_;
}

conn *get_connlist(int n);
int send_list(int fd, node *list);
int set_event(int fd, int event, int flag);
int conn_register(int fd, RCALLBACK in_callback, RCALLBACK out_callback);
int setNonblock(int fd);
int setReUseAddr(int fd);
int conn_close(int fd);
int close_connlist(conn *clist, int n);
int send_list(int fd, node *list);

// 发送链表节点
int send_list(int fd, node *list)
{
    // printf("Sending list on fd %d:\n", fd);
    int sent_total = 0;
    node *current = list->next;
    int idx = conn_list_[fd].idx;
    while (current != list)
    {
        int sent = send(fd, (current->data) + idx, current->length - idx, 0);
        if (sent < 0)
        {
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                // 套接字缓冲区满，无法继续发送
                break;
            }

            else
            {
                // 其他错误，关闭连接
                return -1;
            }
        }


        sent_total += sent;

        // 确保把单个包的数据完整发出去
        if (sent < current->length)
        {
            conn_list_[fd].idx += sent;
            break;
        }

        // printf("%.*s", current->length, current->data);

        
        node *temp = current;
        current = current->next;
        idx =  conn_list_[fd].idx = 0;

        delete_node(temp, list);
        
    }

    conn_list_[fd].sent += sent_total;

    return sent_total;
}


// 设置非阻塞
int setNonblock(int fd)
{
    int flags;

    flags = fcntl(fd, F_GETFL, 0);
    if (flags < 0)
        return flags;
    flags |= O_NONBLOCK;
    if (fcntl(fd, F_SETFL, flags) < 0)
        return -1;
    return 0;
}

// 设置端口复用
int setReUseAddr(int fd)
{
    int reuse = 1;
    return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
}

// 设置事件
int set_event(int fd, int event, int flag)
{
    struct epoll_event ev;
    ev.events = event;
    ev.data.fd = fd;

    if (flag == 0) // 还未加入epfd
    {
        epoll_ctl(epfd_, EPOLL_CTL_ADD, fd, &ev);
    }

    else if (flag == 1) // 已经加入了
    {
        epoll_ctl(epfd_, EPOLL_CTL_MOD, fd, &ev);
    }

    else if (flag == -1)
    {
        epoll_ctl(epfd_, EPOLL_CTL_DEL, fd, NULL);
    }

    return 0;
}

// 获取连接列表
conn *get_connlist(int n)
{
    conn_list_ = (conn *)kvs_malloc(sizeof(conn) * n);
    memset(conn_list_, 0, sizeof(conn) * n);
    return conn_list_;
}

int fill_with_list(char* buffer, int len, node* link)
{
    int idx = strlen(buffer);
    //printf("fill_with_list\n");
    //printf("idx:%d\n",idx);
    
    
    int cpy_len = 0;

    node* node = link->next;
    while(node != link)
    {
        int node_len = node->length;
        if (node_len > len - cpy_len)
        {
            memcpy(buffer+idx+cpy_len, node->data, len - cpy_len);
            cpy_len = len;
            break;
        }
        else
        {
            memcpy(buffer+idx+cpy_len, node->data, node_len);
            cpy_len += node_len;
            node = node->next;
        }
    }

    //printf("cpy_len:%d\n", cpy_len);

    return cpy_len;
}


// 注册连接
int conn_register(int fd, RCALLBACK in_callback, RCALLBACK out_callback)
{

    conn_list_[fd].fd = fd;
    conn_list_[fd].sent = 0;
    conn_list_[fd].idx = 0; // 记录单个包发送部分时指向的位置


    conn_list_[fd].remain_len = 0;
    list_init(&conn_list_[fd].remain_link);
    conn_list_[fd].remain_link.length = 0;

    conn_list_[fd].in_callback = in_callback;
    conn_list_[fd].out_callback = out_callback;

    // 初始化链表节点
    list_init(&conn_list_[fd].rlink);
    conn_list_[fd].rlink.length = 0; // 链表内字节数据总长度

    list_init(&conn_list_[fd].wlink);
    conn_list_[fd].wlink.length = 0; // 链表内字节数据总长度

    return 0;
}

// 关闭连接
int conn_close(int fd)
{
    clear_list(&conn_list_[fd].rlink);
    clear_list(&conn_list_[fd].wlink);

    conn_list_[fd].fd = 0;
    memset(&conn_list_[fd], 0, sizeof(conn));
    epoll_ctl(epfd_, EPOLL_CTL_DEL, fd, NULL);
    close(fd);
    return 0;
}

// 关闭连接列表
int close_connlist(conn *clist, int n)
{
    for (int i = 0; i < n; i++)
    {
        if (clist[i].fd != 0)
        {
            conn_close(clist[i].fd);
        }
    }

    free(clist);
    return 0;
}

#endif